import java.sql.Connection
import java.sql.DriverManager
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.SQLException
import java.text.SimpleDateFormat
import java.util.regex.Matcher
import java.util.regex.Pattern

/**
 * 快捷生成Entity、Service、Mapper 脚本
 *
 * @author pan.shun
 * @since 2022/7/17 22:15
 */

static void main(String[] args) {
    // 点击开始
    start()
}

/**
 * 数据源配置
 */
interface DB_CONFIG {
    String USER_NAME = "root";
    String PASSWORD = "1qa@WS3ed";
//    String JDBC_URL = "jdbc:mysql://127.0.0.1:3306/" + DB_CONFIG.DB_NAME + "?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false";
    String JDBC_URL = "jdbc:mysql://192.168.52.96:3306/report_design?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
    String DB_NAME = "report_design";
    String TABLE_NAME = "gc_user";
}

interface CONSTANT {
    /**
     * 文件生成路径
     */
    String filePath = new File("").getAbsolutePath() + "/generatorFile/";
    /**
     * 是否使用swagger
     */
    Boolean ifUseSwagger = true;
    /**
     * 是否使用公共Entity
     */
    Boolean ifUseCommonEntity = true;
    /**
     * 公共字段
     */
    List<String> commonField = new ArrayList<>(Arrays.asList("id", "createTime", "updateTime", "delFlag"));
    SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm");

    Pattern linePattern = Pattern.compile("_(\\w)");
}

static start() {
    File file = new File(CONSTANT.filePath);
    if (!file.exists()) {
        file.mkdir();
    }
    generatorEntity();
    generatorMapper();
    generatorService();
}

/**
 * 作者信息
 */
private static authorInfo(FileWriter writer) throws IOException {
    writer.write("/**\r\n * @author pan.shun\r\n * @version 2.0\r\n * @since " + CONSTANT.FORMAT.format(new Date()) + "\r\n */\r\n");
}

/**
 * 一键生成Mapper
 */
private static generatorMapper() {
    FileWriter writer = null;
    try {
        writer = new FileWriter(CONSTANT.filePath + lineToHump(DB_CONFIG.TABLE_NAME, true) + "Mapper.java");
        writer.write("import com.baomidou.mybatisplus.core.mapper.BaseMapper;\r\n");
        writer.write("import org.springframework.stereotype.Repository;\r\n\r\n");
        authorInfo(writer);
        writer.write("@Repository\r\n");
        writer.write("public interface " + lineToHump(DB_CONFIG.TABLE_NAME, true)
                + "Mapper extends BaseMapper<" + lineToHump(DB_CONFIG.TABLE_NAME, true) + "Entity> {\r\n}\r\n");
        println("一键生成Mapper成功")
    } catch (Exception ignored) {
        println("一键生成Mapper 流写入失败")
    } finally {
        if (null != writer) {
            try {
                writer.close();
            } catch (Exception ignored) {
            }
        }
    }
}

/**
 * 一键生成Service
 */
private static generatorService() {
    FileWriter writer = null;
    try {
        writer = new FileWriter(CONSTANT.filePath + lineToHump(DB_CONFIG.TABLE_NAME, true) + "Service.java");
        writer.write("import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\r\n");
        writer.write("import lombok.extern.slf4j.Slf4j;\r\n");
        writer.write("import org.springframework.stereotype.Service;\r\n\r\n");
        authorInfo(writer);
        writer.write("@Slf4j\r\n");
        writer.write("@Service\r\n");
        writer.write("public class " + lineToHump(DB_CONFIG.TABLE_NAME, true) + "Service extends ServiceImpl<"
                + lineToHump(DB_CONFIG.TABLE_NAME, true) + "Mapper, "
                + lineToHump(DB_CONFIG.TABLE_NAME, true) + "Entity> {\r\n}\r\n");
        println("一键生成Service成功")
    } catch (Exception ignored) {
        println("一键生成Service 流写入失败")
    } finally {
        if (null != writer) {
            try {
                writer.close();
            } catch (Exception ignored) {
            }
        }
    }
}

/**
 * 一键生成实体类
 */
private static generatorEntity() {
    List<Map<String, String>> tableInfo = getTableInfo();
    if (tableInfo == null || tableInfo.size() == 0) {
        throw new RuntimeException("数据源配置有误");
    }

    FileWriter writer = null;
    try {
        writer = new FileWriter(CONSTANT.filePath + lineToHump(DB_CONFIG.TABLE_NAME, true) + "Entity.java");
        writer.write("import com.baomidou.mybatisplus.annotation.TableName;\r\n");
        if (CONSTANT.ifUseSwagger) {
            writer.write("import io.swagger.annotations.ApiModel;\r\n");
            writer.write("import io.swagger.annotations.ApiModelProperty;\r\n");
        }
        writer.write("import lombok.Data;\r\n\r\n");
        authorInfo(writer);
        writer.write("@Data\r\n");
        writer.write("@TableName(\"" + DB_CONFIG.TABLE_NAME.toUpperCase() + "\")\r\n");
        if (CONSTANT.ifUseSwagger) {
            writer.write("@ApiModel\r\n");
        }
        writer.write("public class " + lineToHump(DB_CONFIG.TABLE_NAME, true) + "Entity");
        if (CONSTANT.ifUseCommonEntity) {
            writer.write(" extends CommonEntity {\r\n");
        } else {
            writer.write(" {\r\n");
        }

        for (Map<String, String> r : tableInfo) {
            String columnName = r.get("columnName");
            String dataType = r.get("dataType");
            String columnComment = r.get("columnComment");

            boolean flag = true;
            if (CONSTANT.ifUseCommonEntity) {
                flag = !CONSTANT.commonField.contains(columnName);
            }
            if (flag) {
                if (isNotEmpty(columnComment)) {
                    if (CONSTANT.ifUseSwagger) {
                        writer.write("    @ApiModelProperty(value = \"" + columnComment + "\")\r\n");
                    } else {
                        writer.write("    /**\r\n     * " + columnComment + "\r\n" + "     */\r\n");
                    }
                } else {
                    if (CONSTANT.ifUseSwagger) {
                        writer.write("    @ApiModelProperty(value = \"无\")\r\n");
                    }
                }
                writer.write("    private " + dataType + " " + columnName + ";\r\n\r\n");
            }
        }
        writer.write("}\r\n");
        println("一键生成Entity成功")
    } catch (Exception ignored) {
        throw new RuntimeException("一键生成实体类 流写入失败");
    } finally {
        if (null != writer) {
            try {
                writer.close();
            } catch (Exception ignored) {
            }
        }
    }

}

private static boolean isNotEmpty(Object str) {
    return str != null && "" != str;
}

private static Connection getConn() {
    Connection connection = null;
    try {
        connection = DriverManager.getConnection(DB_CONFIG.JDBC_URL, DB_CONFIG.USER_NAME, DB_CONFIG.PASSWORD);
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return connection;
}

private static List<Map<String, String>> getTableInfo() {
    List<Map<String, String>> list = new ArrayList<>(16);
    Connection conn = getConn();
    try {
        String querySql = "SELECT `COLUMN_NAME` ,`DATA_TYPE` ,`COLUMN_COMMENT` FROM information_schema.columns WHERE table_schema =? AND table_name = ?;";
        PreparedStatement preparedStatement = conn.prepareStatement(querySql);
        preparedStatement.setString(1, DB_CONFIG.DB_NAME);
        preparedStatement.setString(2, DB_CONFIG.TABLE_NAME);
        ResultSet rs = preparedStatement.executeQuery();
        while (rs.next()) {
            Map<String, String> map = new HashMap<>(16);
            String columnName = rs.getString(1);
            String dataType = rs.getString(2);
            String columnComment = rs.getString(3);
            map.put("columnName", lineToHump(columnName, false));
            map.put("dataType", mySqlType2JavaType(dataType));
            map.put("columnComment", columnComment);
            list.add(map);
        }
        return list;
    } catch (Exception e) {
        throw new RuntimeException(e)
    } finally {
        if (null != conn) {
            try {
                conn.close();
            } catch (Exception e) {
            }
        }
    }

}

private static String mySqlType2JavaType(String dataType) {
    if ("VARCHAR".equalsIgnoreCase(dataType) || "TEXT".equalsIgnoreCase(dataType) || "LONGTEXT".equalsIgnoreCase(dataType) || "CHAR".equalsIgnoreCase(dataType)) {
        return "String";
    } else if ("DATE".equalsIgnoreCase(dataType) || "DATETIME".equalsIgnoreCase(dataType) || "TIMESTAMP".equalsIgnoreCase(dataType)) {
        return "java.util.Date";
    } else if ("INT".equalsIgnoreCase(dataType) || "INTEGER".equalsIgnoreCase(dataType) || "TINYINT".equalsIgnoreCase(dataType)) {
        return "Integer";
    } else if ("BIGINT".equalsIgnoreCase(dataType)) {
        return "Long";
    } else if ("FLOAT".equalsIgnoreCase(dataType)) {
        return "Float";
    } else if ("DOUBLE".equalsIgnoreCase(dataType)) {
        return "Double";
    } else {
        throw new RuntimeException("当前数据类型【" + dataType + "】没有与之匹配的数据类型");
    }
}

/**
 * 下划线转驼峰
 */
private static String lineToHump(String str, boolean ifCapture) {
    str = str.toLowerCase();
    Matcher matcher = CONSTANT.linePattern.matcher(str);
    StringBuffer sb = new StringBuffer();
    while (matcher.find()) {
        matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
    }
    matcher.appendTail(sb);
    String v = sb.toString();
    if (ifCapture) {
        return captureName(v);
    } else {
        return v;
    }
}

/**
 * 首字母大写
 */
private static String captureName(String name) {
    name = name.substring(0, 1).toUpperCase() + name.substring(1);
    return name;

}
